iT邦幫忙

2022 iThome 鐵人賽

DAY 24
0
DevOps

Azure DevOps進階應用系列 第 24

【Azure DevOps進階應用】多專案命名規則與變數範本

  • 分享至 

  • xImage
  •  

我們前面會將大部份的YAML設計都改成範本的主要原因就是為了大部份的內容可以重複使用,並且在需要調整需修改的時候不需要每一個專案都去修改,所以會建立多個Azure DevOps專案應該是可以預期的。

不過每一個專案名稱除了使用在Azure DevOps專案上之外,還有程式碼的專案/方案名稱、GCP Artifact Registry的名稱、GCP CloudRun的名稱,所以命名規則儘可能一致是必要的,名稱一致在很多事情上也比較方便。

有些人可能會使用像命名空間的方式來取名,利用點符號「.」來區隔階層,有些地方無法使用點符號卻可以使用減符號「-」或底線符號「_」,甚至有些服務只允許小寫名稱。使用什麼符號這些其實都還好,只要不是DevOps專案叫AAA,程式碼專案叫BBB,使用到的服務又用CCC就沒那麼麻煩。

一旦規則清楚,許多東西其實就不見得需要放在專案的設定內,可以將共同會有的設定值提取到範本專案中來設定,這跟程式設計進行抽象化把共同的東西放到最底層(最上層)的意思是一樣的。

這時候再回頭來看一遍前一篇的YAML截圖,會發現其實有很多東西應該是可以被提取出來的,也就是變數Variables的那一個區段,很多其實在每一個專案可能都會去設定它,但是內容卻是幾乎一樣的。

https://ithelp.ithome.com.tw/upload/images/20221009/200339610BASgtVFDE.png

像是CloudRun的Region、ProjectId就一定是不會變的,所以這一篇我們就要來將這些內容抽出來做成變數範本(variables template)。

變數改成範本的規則和其它的範本差不多,就是從Variables開始下手,在Pipeline YAML原本的Variables底下也是使用template關鍵字來引用已改為範本的內容。

不過這邊我想要把它分為三個部份,分別是:

  1. 與程式語言無關的最上層共用變數範本
  2. 與程式語言相關的變數範本
  3. 專案專用的變數範本

因為實際上可能碰到的情況是Azure DevOps內有許多不同的專案,每一個專案使用的程式語言可能都不一樣,至少如果有開發手持裝置App的需求的話,就一定會有後端語言和App語言不同的情況。碰到這種情況,有些變數就不會是另一種程式語言/範本需要設定的內容,像是圖中的slnOrCsprojName這個變數,就是為了.Net語言而設定的變數。

所以在範本專案的Git Repo裡面我會建立下面的目錄結構與檔案

variables
  variables-template.yaml
  dotnet
    variables-template.yaml
  ios
    variables-template.yaml

在variables目錄底下會有一個variables-template.yaml檔案,這裡面是存放共用的變數設定。同樣的在variables目錄底下也會有不同語言的目錄,例如dotnet、ios,然後裡面再放一個variables-template.yaml。

上面這樣子就完成了1和2的設計了,剩下的3當然就是要放在專案自己的Git Repo裡面啦!所以在專案的Pipelines Git Repo裡面也會有個variables目錄,不過底下的檔案名稱就不會有template字樣了,畢竟它不是範本專案嘛!

variables
  dotnet-variables.yaml
  ios-variables.yaml

這邊我是直接以程式語言的名稱為前綴命名,方便一眼就識別出來是哪一個程式語言使用的變數檔,如果要分得再細一點的話,其實應該會再區分是給PR Pipeline使用的?還是給CI Pipeline使用的?例如:dotnet-ci-variables.yaml

知道檔案怎麼區分之後,接下來就直接把現有的變數移到各自的檔案中吧!

# variables/variables-template.yaml

variables:
  templateResourceName: templates
  pipelineResourceName: pipelines
  sourceResourceName: sources
  lowerCaseProjectName: $[lower(variables['normalProjectName'])]
  hyphenLowerCaseProjectName: $[replace(variables['lowerCaseProjectName'], '.', '-')]
  pipelineArtifact: output
  buildResultZipName: buildResult.zip

  #==== docker image configuration ====
  imgRepository: asia-east1-docker.pkg.dev/feisty-mechanic-363012/$(lowerCaseProjectName)/web

  #==== if deploy to Cloud Run ====
  imgRegistryService: GCPArtifactRegistry-$(normalProjectName)
  cloudRunServiceName: $(lowerCaseProjectName)
  cloudRunRegion: asia-east1
  cloudRunProjectId: feisty-mechanic-363012
# variables/dotnet/variables-template.yaml

variables:
  codeType: net
  slnOrCsprojName: $(normalProjectName).sln
  buildConfiguration: 'release' # debug/release
  startFileName: $(normalProjectName).dll
# (專案的) variables/dotnet-variables.yaml

variables:
  normalProjectName: DemoProject

上面的YAML內容剛好依照了1、2、3的順序列出來,但是如果要看懂的話,可能要從3開始看,也就是在專案內的變數檔最後只剩下設定了它的專案名稱,也就是normalProjectName這個變數。normalProjectName這個變數會在共用的變數範本檔(最上面的那個)裡面被lower函數用來轉為全小寫的lowerCaseProjectName變數,另外還有一個hyphenLowerCaseProjectName變數則是將lowerCaseProjectName變數中的點符號「.」轉為減符號「-」(如果有),也就是如果專案名稱是使用命名空間的格式來取名稱,像是AAA.BBB.CCC這樣,那在hyphenLowerCaseProjectName變數中就會變成aaa-bbb-ccc,在某些服務上比較適合這樣的格式。

也因為已經將專案名稱進行了一些轉換,所以後續的其它變數就會依照需要來取用適合的變數,例如imgRepository的設定中就使用到了lowerCaseProjectName變數,而imgRegistryService則是使用了normalProjectName變數(就是Service Connection分享給其它專案時預設的格式),cloudRunServiceName則是佈署的時候使用小寫的專案名稱。

在語言差異的共用變數範本中則是將normalProjectName變數用在了sln與dll檔案名稱上,在這個變數範本中另外有一個codeType變數,是為了可以在處理程式語言的範本變多的時候,利用條件式判斷來決定要插入使用哪一個範本。

上面三個變數檔都各自就位之後,最後就是修改最上面截圖的CI Pipeline YAML內容了,修改後的內容如下:

trigger:
- none

resources:
  repositories:
  - repository: sources
    type: git
    name: DemoProject/NetApp
    ref: Develop
    trigger:
      branches:
        include:
          - Develop
  - repository: pipelines
    type: git
    name: DemoProject/Pipelines
    ref: main
  - repository: templates
    type: git
    name: ironman2022/templates
    ref: main

variables:
  - template: variables/variables-template.yaml@templates
  - template: variables/dotnet/variables-template.yaml@templates
  - template: ../variables/dotnet-variables.yaml

stages:
  - template: stages/dotnet-build-stage.yaml@templates
    parameters:
      sourcePath: $(Build.SourcesDirectory)
      slnOrCsprojName: $(slnOrCsprojName)
      artifactName: $(pipelineArtifact)
      unzip: true
      zipFileName: $(buildResultZipName)
      unzipToFolderPath: $(System.ArtifactsDirectory)/buildImage
      imgRepository: $(imgRepository)
      imgTags: |
        latest
        $(Build.BuildId)
      buildDockerfile: $(buildDockerfile)
      buildContext: $(System.ArtifactsDirectory)/buildImage
      containerRegistry: ${{ variables.imgRegistryService }}
      startFileName: $(startFileName)
      templateResourceName: ${{ variables.templateResourceName }}
  - template: stages/deploy-cloudrun-stage.yaml@templates
    parameters:
      cloudRunProjectId: $(cloudRunProjectId)
      imgRepository: $(imgRepository)
      cloudRunRegion: $(cloudRunRegion)
      cloudRunServiceName: $(cloudRunServiceName)
      templateResourceName: ${{ variables.templateResourceName }}
      pipelineResourceName: ${{ variables.pipelineResourceName }}

上面在variables區段就是全部改用了變數範本,順序就是前面提到的1、2、3,要留意的是只有第1個和第2個最後有@符號,代表引用範本專案內的檔案。

仔細看上面的YAML內容的話,你可能會覺得不太對勁,怎麼會有些地方是用$(變數名稱),有些地方卻是用${{ variables.變數名稱 }}呢?

如果你還記得認識Build Pipeline的運算式與函數這篇內容提到的巨集運算式與編譯時期的運算式的話,就會知道前者是常用的巨集式用法,後者是編譯時期的用法。因為我們定義的有些變數是內嵌式還有引用到變數(imgRegistryService變數內用到其它變數),或是其它原因,所以無法使用巨集式的用法,這時候改用後者就可以解決這樣的問題。

通常這是改完要執行的時候碰到錯誤訊息,上面會告訴你哪一些變數它當時無法解析,可以先改列出來的那些項目,或是全部都改用後者(因為目前到這裡沒有動態改到變數的地方,所以沒差)。


上一篇
【Azure DevOps進階應用】進階版-建立CI Pipeline
下一篇
【Azure DevOps進階應用】重構YAML範本:加入更多彈性
系列文
Azure DevOps進階應用30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言